package cn.edu.anan.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * 脱敏处理切面，根据JasyptMethod、JasyptField注解进行处理
 *
 * @author ThinkPad
 * @version 1.0
 * @date 2021/9/1 7:00
 */
@Component
@Aspect
@Slf4j
public class JasyptAspect {

    /**
     * 注入加解密 Encryptor
     */
    @Autowired
    private StringEncryptor stringEncryptor;

    @Pointcut("@annotation(cn.edu.anan.aop.JasyptMethod)")
    public void jasyptPointCut() {
    }

    /**
     * 脱敏处理通知-环绕通知
     * @param pjp
     * @return
     */
    @Around("jasyptPointCut()")
    public Object jasyptAround(ProceedingJoinPoint pjp) {
        // 1.参数加密处理
        encrypt(pjp);

        // 2.返回值解密处理
        Object result = decrypt(pjp);
        // 响应前，还原数据
        log.info("3.响应前，还原数据：{}", result);
        return result;

    }

    /**
     * 封装加密处理
     * @param pjp
     */
    private void encrypt(ProceedingJoinPoint pjp){
        try {
            Object[] objects = pjp.getArgs();
            if (objects.length != 0) {
                for (Object o : objects) {
                    // 简单类型加密
                    if (o instanceof String) {
                        o = stringEncryptor.encrypt(String.valueOf(o));
                    } else {
                        // 引用类型加密
                        if(Objects.nonNull(o)){

                            // 打印输出原参数
                            log.info("1.脱敏前，原请求参数：{}", o);

                            // 脱敏
                            Field[] fields = o.getClass().getDeclaredFields();
                            for(Field f : fields){
                                boolean yes = f.isAnnotationPresent(JasyptField.class);
                                if(yes){
                                    f.setAccessible(true);
                                    String realValue = (String)f.get(o);
                                    String encryptValue = stringEncryptor.encrypt(realValue);
                                    f.set(o,encryptValue);
                                }
                            }
                        }
                    }
                }
            }
        } catch (IllegalAccessException e) {
            log.error("jasypt 加密处理异常，异常消息：{}", e.getMessage());
        }
    }

    /**
     * 封装解密处理
     * @param pjp
     * @return
     */
    private Object decrypt(ProceedingJoinPoint pjp) {
        Object result = null;
        try {
            result = pjp.proceed();
            if (Objects.nonNull(result)) {
                if (result instanceof String) {
                    result = stringEncryptor.decrypt(String.valueOf(result));
                } else {
                    Field[] fields = result.getClass().getDeclaredFields();
                    for(Field f : fields){
                        boolean yes = f.isAnnotationPresent(JasyptField.class);
                        if(yes){
                            f.setAccessible(true);
                            String encryptValue = (String)f.get(result);
                            String realValue = stringEncryptor.decrypt(encryptValue);
                            f.set(result,realValue);
                        }
                    }
                }
            }
        } catch (Throwable e) {
            log.error("jasypt 解密处理异常，异常消息：{}", e.getMessage());
        }
        return result;
    }

}
